package com.nulldev.util.web.flexibleKit.ref_browser;

import java.awt.BorderLayout;
import java.awt.Component;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JScrollPane;
import javax.swing.JButton;
import java.awt.FlowLayout;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

import com.nulldev.util.JVM.Arguments;
import com.nulldev.util.JVM.JVM;
import com.nulldev.util.concurrency.threadIt.v4.emapi.ExecutorManager;
import com.nulldev.util.graphics.renderIt.api.renderItAPI;
import com.nulldev.util.graphics.renderIt.api.core.IRenderCanvas;
import com.nulldev.util.graphics.renderIt.api.core.renderItOutputType;
import com.nulldev.util.graphics.renderIt.api.envcaps.renderItCanvasOperations;
import com.nulldev.util.gui.swingAPI.Swing;
import com.nulldev.util.gui.themeAPI.Theme;
import com.nulldev.util.gui.themeAPI.ThemeAPI;
import com.nulldev.util.gui.themeAPI.ThemeAPI.ThemingOptions;
import com.nulldev.util.io.file.FileUtil;
import com.nulldev.util.web.HttpClient.HttpClient;
import com.nulldev.util.web.HttpClient.HttpResponse;
import com.nulldev.util.web.URLUtils.URLUtils;
import com.nulldev.util.web.flexibleKit.builtin_pages.BuiltInPageResource;
import com.nulldev.util.web.flexibleKit.flexRenderer.FlexRenderer;
import com.nulldev.util.web.flexibleKit.general.flexDocument;
import com.nulldev.util.web.flexibleKit.general.flexKit;
import com.nulldev.util.web.flexibleKit.jfvParse.Document;
import com.nulldev.util.web.flexibleKit.jfvParse.JFiveParse;
import com.nulldev.util.web.flexibleKit.general.flexDocument.DocumentFlags;

import javax.swing.JLabel;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JMenuBar;
import javax.swing.JMenu;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JMenuItem;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.Reader;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;

public class flexBrowser extends JFrame {

	private static final long serialVersionUID = -5381018752877297114L;
	private JPanel contentPane;
	private JTextField txtFlexWelcome;

	private FlexRenderer fr;
	private JLabel lblNewLabel;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		Arguments.setup(args);
		Swing.enableAA();
		Swing.enableJSO();
		ExecutorManager.get().execute(new Runnable() {
			public void run() {
				try {
					final flexBrowser frame = new flexBrowser();
					frame.setVisible(true);
					ThemeAPI.applySwingTheme(Theme.SwingTheming.SWING_LIGHT, frame, ThemingOptions.APPLY_SYSTEM_LOOK_AND_FEEL,
							ThemingOptions.APPLY_SYSTEM_FONT);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the frame.
	 */
	public flexBrowser() {
		setTitle("flexKit Reference Browser.");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 640, 480);

		JMenuBar menuBar = new JMenuBar();
		setJMenuBar(menuBar);

		JMenu mnNewMenu = new JMenu("File");
		menuBar.add(mnNewMenu);

		JMenuItem mntmNewMenuItem = new JMenuItem("Exit.");
		mntmNewMenuItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				JVM.exit();
			}
		});
		mnNewMenu.add(mntmNewMenuItem);

		JMenu mnNewMenu_1 = new JMenu("flexKit");
		menuBar.add(mnNewMenu_1);

		JCheckBoxMenuItem chckbxmntmNewCheckItem = new JCheckBoxMenuItem("Enable JS parsing");
		mnNewMenu_1.add(chckbxmntmNewCheckItem);

		JCheckBoxMenuItem chckbxmntmNewCheckItem_1 = new JCheckBoxMenuItem("Enable CSS parsing");
		mnNewMenu_1.add(chckbxmntmNewCheckItem_1);

		JCheckBoxMenuItem chckbxmntmNewCheckItem_2 = new JCheckBoxMenuItem("Draw bounds");
		chckbxmntmNewCheckItem_2.setSelected(true);
		mnNewMenu_1.add(chckbxmntmNewCheckItem_2);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		setContentPane(contentPane);
		contentPane.setLayout(new BorderLayout(0, 0));

		JScrollPane scrollPane = new JScrollPane();
		contentPane.add(scrollPane, BorderLayout.CENTER);

		JPanel panel = new JPanel();
		scrollPane.setColumnHeaderView(panel);
		panel.setLayout(new BorderLayout(0, 0));

		JButton btnNewButton_2 = new JButton("Go!");

		txtFlexWelcome = new JTextField();
		txtFlexWelcome.addKeyListener(new KeyAdapter() {
			@Override
			public void keyReleased(KeyEvent e) {
				if (e.getExtendedKeyCode() == KeyEvent.VK_ENTER) {
					e.consume();
					btnNewButton_2.setEnabled(false);
					try {
						final String url = txtFlexWelcome.getText();
						if (url == null || url.isEmpty() || !URLUtils.isValid(url)) {
							return;
						} else {
							openURL(url);
						}
					} catch (Exception ex) {
						// TODO: Add back the dialogs from nullUtil 2.x (imo they were great fun)
						JVM.errorln(ex);
					} finally {
						btnNewButton_2.setEnabled(true);
					}
					return;
				}
			}
		});
		txtFlexWelcome.setText("flex://welcome");
		panel.add(txtFlexWelcome, BorderLayout.CENTER);
		txtFlexWelcome.setColumns(50);

		btnNewButton_2.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				btnNewButton_2.setEnabled(false);
				try {
					final String url = txtFlexWelcome.getText();
					if (url == null || url.isEmpty() || !URLUtils.isValid(url)) {
						return;
					} else {
						openURL(url);
					}
				} catch (Exception ex) {
					// TODO: Add back the dialogs from nullUtil 2.x (imo they were great fun)
					JVM.errorln(ex);
				} finally {
					btnNewButton_2.setEnabled(true);
				}
			}
		});
		panel.add(btnNewButton_2, BorderLayout.EAST);

		JPanel panel_1 = new JPanel();
		FlowLayout flowLayout = (FlowLayout) panel_1.getLayout();
		flowLayout.setVgap(0);
		flowLayout.setHgap(0);
		panel.add(panel_1, BorderLayout.WEST);

		JButton btnNewButton = new JButton("←");
		panel_1.add(btnNewButton);

		JButton btnNewButton_1 = new JButton("→");
		panel_1.add(btnNewButton_1);

		JPanel panel_2 = new JPanel();
		FlowLayout flowLayout_1 = (FlowLayout) panel_2.getLayout();
		flowLayout_1.setAlignment(FlowLayout.LEADING);
		flowLayout_1.setVgap(0);
		contentPane.add(panel_2, BorderLayout.SOUTH);

		lblNewLabel = new JLabel("flexKit " + flexKit.VERSION);
		panel_2.add(lblNewLabel);

		addComponentListener(new ComponentAdapter() {
			@Override
			public void componentShown(ComponentEvent e) {
				final IRenderCanvas canvas = renderItAPI.make_instance(renderItOutputType.RIT_OUTPUT_TYPE_SWING_FRAME, flexBrowser.this);
				if (canvas.supportsOperation(renderItCanvasOperations.RIT_output_awt_component)) {
					scrollPane.setViewportView((Component) canvas.asAWTComponent());
				} else {
					scrollPane.setViewportView((Component) canvas.asSwingComponent());
				}
				scrollPane.getVerticalScrollBar().setUnitIncrement(16);
				flexBrowser.this.fr = new FlexRenderer(canvas, scrollPane);
				canvas.setRenderCallback(fr);
				ExecutorManager.get().execute(() -> {
					canvas.start();
				});
				chckbxmntmNewCheckItem_2.setSelected(flexBrowser.this.fr.DEBUG_RENDER_ELEMENT_HUD.get());
			}
		});

		chckbxmntmNewCheckItem_2.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				flexBrowser.this.fr.DEBUG_RENDER_ELEMENT_HUD.set(chckbxmntmNewCheckItem_2.isSelected());
			}
		});
	}

	public void openURL(final String url) throws Exception {
		ExecutorManager.globalAsyncSubmit(() -> {
			try {
				if (url.equalsIgnoreCase("about:gpu")) {
					final Document d = JFiveParse.parse(FileUtil.getResourceAsString(BuiltInPageResource.class, "flexkit_gpu.html"));
					final flexDocument fd = new flexDocument(url, d, DocumentFlags.DISABLE_JS_PARSER, DocumentFlags.DISABLE_CSS_PARSER);
					lblNewLabel.setText("Binding page...");
					SwingUtilities.invokeLater(() -> {
						fr.bindDocument(fd);
						lblNewLabel.setText("Loaded.");
					});
					this.txtFlexWelcome.setText(url);
				} else if (URLUtils.isValid(url)) {
					lblNewLabel.setText("Downloading page...");
					final HttpResponse<Reader> x = HttpClient.getReader().url(url).forceHeader("User-Agent", flexKit.getUserAgent()).create();
					final Document d = JFiveParse.parse(x.data());
					x.adaptiveClose();
					lblNewLabel.setText("Parsing page...");
					final flexDocument fd = new flexDocument(url, d, DocumentFlags.DISABLE_JS_PARSER, DocumentFlags.DISABLE_CSS_PARSER);
					lblNewLabel.setText("Binding page...");
					SwingUtilities.invokeLater(() -> {
						fr.bindDocument(fd);
						lblNewLabel.setText("Loaded.");
					});
					this.txtFlexWelcome.setText(url);
				} else {
					throw new UnsupportedOperationException("Invalid URL: " + url);
				}
			} catch (Exception ex) {
				throw new RuntimeException(ex);
			}
			return null;
		});
	}

	protected JLabel getLblNewLabel() {
		return lblNewLabel;
	}
}
